package org.idtem.utils.freeling;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.idtem.utils.FileUtils;
import org.idtem.utils.constants.Constants;
import org.idtem.utils.constants.Constants.Common;
import org.idtem.utils.freeling.SentenciaFreeling;
import org.idtem.utils.logger.LoggerHelper;

public class RunComandFreeling {

	private static final String DIR = "c:/Freeling/";
	public static final String NEWLINE = "\n";
	private static Logger logger;

	public static int WORD = 0;
	public static int LEMA = 1;
	public static int EAGLES = 2;
	public static int PROB = 3;
	public static int OFFSETS = 4;
	private static final String NOMBRE_ARCHIVO_TEMPORAL = "";
	private static final String RUTA_ARCHIVO_TEMPORAL = "ISRTFreeling.txt";
	private static final String FULL_PATH_FILE = RUTA_ARCHIVO_TEMPORAL + NOMBRE_ARCHIVO_TEMPORAL;
	
	public static Collection<SentenciaFreeling> analizarInputFrase(String frase) {
		LoggerHelper.getInstance().getFreeling2ComponentLogguer().info("FREELING - PROCESSING - FRASE");
		return analizarInput(frase, false);
	}


	public static Collection<SentenciaFreeling> analizarInputDocumento(String docText) {
		LoggerHelper.getInstance().getFreeling2ComponentLogguer().info("FREELING - PROCESSING - DOCUMENT");
		return analizarInput(docText, Constants.System.USAR_ARCHIVO);
	}																	   
	
	private static Collection<SentenciaFreeling> analizarInput(String doc, boolean usarPreprocesamiento){
		String resultFreeling = null;
		String documento = null;
		try {
	    	FileUtils.delete(FULL_PATH_FILE);
	    	FileUtils.createFile(FULL_PATH_FILE, doc);
	    }
	    catch(java.io.IOException ioex) 
	    {
	    	LoggerHelper.getInstance().getFreeling2ComponentLogguer().error("Se presento el error: " + ioex.toString());
	    }		
	    String comando = "cmd.exe /C "+ DIR + "analyzer.exe";
	    String parametros = "-f";
	    String configuracion = DIR + "es.cfg";
	    String inputFile = "< " + FULL_PATH_FILE;
	    String comandoStr = comando + " " + parametros + " " + configuracion + " " + inputFile;
	    LoggerHelper.getInstance().getFreeling2ComponentLogguer().info(comandoStr);
	    Process proc;
		documento = FileUtils.readFile(FULL_PATH_FILE);
		try {
			proc = Runtime.getRuntime().exec(comandoStr);
						
			resultFreeling = interact(proc, documento);
		} catch (IOException e1) {
			e1.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		FileUtils.delete(RUTA_ARCHIVO_TEMPORAL + NOMBRE_ARCHIVO_TEMPORAL);
		return  SentenciaFreeling.ObtenerSentencias(documento, resultFreeling);
		
		
		
	}
	
	private static String interact(final Process process, final String entrada) throws Exception {
		
		capture(new InputStreamReader(process.getErrorStream()));		
		sendInParallel(new OutputStreamWriter(process.getOutputStream()), entrada);
		String salida = null;
		try{ 
			salida = readAll(new InputStreamReader(process.getInputStream()));
			process.getInputStream().close();
			process.waitFor();
		}catch(IOException e1){
			logger.log(Level.SEVERE, "Error al leer el stream de entrada");
			throw new RuntimeException("Error al leer el stream de entrada");
		}catch(InterruptedException e2){
			logger.log(Level.SEVERE, "Error al esperar por el proceso");
			throw new RuntimeException("Error al esperar por el proceso");
		}
		if (process.exitValue() != 0){
			logger.log(Level.SEVERE, "El proceso no termino normalmente\nCodigo = " + process.exitValue());
			throw new RuntimeException("El proceso no termino normalmente\nCodigo = " + process.exitValue());
		}
		return salida;
	}
	
	private static void capture(final Reader reader) {
		new Thread() {
			public void run() {
				try {
					try {
						String str = readAll(reader);
						str.length();
					} finally {
						reader.close();
					}
				} catch (Exception e) {
					logger.log(Level.SEVERE, "Error al leer del proceso");				
				}		
			}
		}.start();
	}
	
	private static void sendInParallel(final Writer writer, final String entrada) {
		// Hay que tener una thread para escribir porque cae en deadlock de otra manera
		new Thread() {
			public void run() {
				try {
					try {
						writer.write(entrada);
					} finally {
						writer.close();
					}
				} catch (Exception e) {
					logger.log(Level.SEVERE, "Error al escribir en el proceso");					
				}		
			}
		}.start();
	}
	
	private static String readAll(Reader reader) throws IOException {
		StringBuilder builder = new StringBuilder();
		char[] buffer = new char[1024];
		while (true) {
			int len = -1;
			len = reader.read(buffer);
			if (len < 0) {
				break;
			}
			builder.append(buffer, 0, len);
		}
		return builder.toString();
	}

	public static ArrayList<AnalisisSintacticoNodoBaseFreeling> analisisSintactico(String docText)
	{
		String resultFreeling = null;
		String documento = null;
		try {
	    	FileUtils.delete(FULL_PATH_FILE);
	    	FileUtils.createFile(FULL_PATH_FILE, docText);
	    }
	    catch(java.io.IOException ioex) 
	    {
	    	LoggerHelper.getInstance().getFreeling2ComponentLogguer().error("Se presento el error: " + ioex.toString());
	    }		
	    String comando = "cmd.exe /C "+ DIR + "analyzer.exe";
	    String parametros = "-f";
	    String configuracion = DIR + "es2.cfg";
	    String inputFile = "< " + FULL_PATH_FILE;
	    String comandoStr = comando + " " + parametros + " " + configuracion + " " + inputFile;
	    LoggerHelper.getInstance().getFreeling2ComponentLogguer().info(comandoStr);
	    Process proc;
		documento = FileUtils.readFile(FULL_PATH_FILE);
		try {
			proc = Runtime.getRuntime().exec(comandoStr);
						
			resultFreeling = interact(proc, documento);
		} catch (IOException e1) {
			e1.printStackTrace();
		} catch (Exception e) {
			e.printStackTrace();
		}
		FileUtils.delete(RUTA_ARCHIVO_TEMPORAL + NOMBRE_ARCHIVO_TEMPORAL);
		try {
			int[] nextIndex = new int[1];
			return AnalisisSintacticoNodoBaseFreeling.ObtenerInformacionSintactica(resultFreeling.split(Common.NEWLINE), 0, nextIndex);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return null;
	}
	
}
